{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Implementation of Graph Overview\n",
    "\n",
    "In this lecture we will implement a simple graph by focusing on the Node class. Refer to this lecture for the solution to the Interview Problem\n",
    "\n",
    "___\n",
    "The graph will be directed and the edges can hold weights.\n",
    "\n",
    "We will have three classes, a State class, a Node class, and finally the Graph class.\n",
    "\n",
    "We're going to be taking advantage of two built-in tools here, [OrderDict](https://docs.python.org/2/library/collections.html#collections.OrderedDict) and [Enum](https://docs.python.org/3/library/enum.html)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from enum import Enum  \n",
    "\n",
    "class State(Enum):\n",
    "    unvisited = 1 #White\n",
    "    visited = 2 #Black\n",
    "    visiting = 3 #Gray"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now for the Node class we will take advantage of the OrderedDict object in case we want to keep trak of the order keys are added to the dictionary."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from collections import OrderedDict\n",
    "\n",
    "class Node:\n",
    "\n",
    "    def __init__(self, num):\n",
    "        self.num = num\n",
    "        self.visit_state = State.unvisited\n",
    "        self.adjacent = OrderedDict()  # key = node, val = weight\n",
    "\n",
    "    def __str__(self):\n",
    "        return str(self.num)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Then finally the Graph:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Graph:\n",
    "\n",
    "    def __init__(self):\n",
    "        self.nodes = OrderedDict()  # key = node id, val = node\n",
    "\n",
    "    def add_node(self, num):\n",
    "        node = Node(num)\n",
    "        self.nodes[num] = node\n",
    "        return node\n",
    "\n",
    "    def add_edge(self, source, dest, weight=0):\n",
    "        if source not in self.nodes:\n",
    "            self.add_node(source)\n",
    "        if dest not in self.nodes:\n",
    "            self.add_node(dest)\n",
    "        self.nodes[source].adjacent[self.nodes[dest]] = weight"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "g = Graph()\n",
    "g.add_edge(0, 1, 5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "OrderedDict([(0, <__main__.Node instance at 0x103a761b8>),\n",
       "             (1, <__main__.Node instance at 0x104dfef80>)])"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "g.nodes"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Great Job!"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
